Haku Gabriel L. Manor Supabase waxaa loo isticmaali karaa in ay u isticmaali karaa macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka. Su'aalaha waxaa laga yaabaa in ay ku yaalaa in ay ku yaalaa in ay ku yaalaa in ay ku yaalaa in ay ku yaalaa in ay ku yaalaa in ay ku yaalaa in ay ku yaalaa. Markaas ka mid ah oo ku saabsan Markaas oo leh. fine-grained permissions relationships between users and data Ma rabtaa in aad u baahan tahay si ay u isticmaali karaa macluumaad ka mid ah macluumaadka iyo macluumaadka, si ay u isticmaali karaa macluumaadka. Tutorials waxaa loo isticmaali karaa sida loo isticmaali karaa ee a adeegyada Supabase authentication and authorization Next.js Waxaan ku faraxsanay Login iyo Session Management waxaa loo isticmaali karaa Haku Sida loo isticmaali karaa iyo a Haku Supabase Auth authorization rules ReBAC (Relationship-Based Access Control) waa mid ka mid ah Supabase Edge Functions local Policy Decision Point (PDP) Ka dibna, aad u baahan tahay app-ka la xiriira-gaarka ah oo loo isticmaali karaa si ay u isticmaali karaa sida macluumaadka ah iyo macluumaadka la isticmaali karaa - iyo nidaamka dhismaha caadiga ah oo aad u isticmaali karaa sida app-ka aad u isticmaali karaa. Sidaa waxa ay u baabuurta Sida loo yaabaa, waxaa loo isticmaali karaa macluumaadka macluumaadka iyo macluumaadka. iyo Markaas oo ka mid ah authentication iyo authorization in action. Supabase Next.js Taageerada waxaa loo isticmaali karaa in la isticmaali karaa in la isticmaali karaa in la isticmaali karaa in la isticmaali karaa in la isticmaali karaa in la isticmaali karaa in la isticmaali karaa. login/signup iyo sida loo isticmaali karaa Waxaad ka mid ah ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah. Supabase Auth authorization policies Waxaan u isticmaali karaa macluumaadka ugu weyn ee Supabase- Haku Haku Haku iyo Qalabka A Qalabka waxaa laga yaqaan "per-user and per-resource access rules". Auth Postgres RLS Realtime Edge Functions Relationship-Based Access Control (ReBAC) Haku Tech Haku Haku Haku Haku Haku Supabase – Backend-as-a-service for database, authentication, real-time, iyo macluumaadka edge Next.js – Framework Frontend ee loo soo saarka UI iyo API routes Permit.io – (ka ReBAC) si ay u helo logic autorization via PDP Supabase CLI – Si loo isticmaali karaa iyo si ay u isticmaali karaa Edge Functions in la soo saarka iyo wax soo saarka Haku Marka: JS Haku.ee Qalabka CLI Qalabka Haku Haku Haku Haku Haku Haku Node.js waxaa la aasaasay Qalabka Account Nala soo xiriir Ku saabsan React/Next.js Shirkadda Repo Ma rabtaa in la isticmaalo app? Dhismaha dhismaha waa mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah. Haku Haku Haku Haku Haku Ma rabtaa in la soo xiriir in la soo xiriir oo la soo xiriir. Waayo, waxaa laga yaabaa in la soo bandhigiisa in la soo bandhigiisa in la soo bandhigiisa in la soo bandhigiisa. Waxaa la heli karaa in ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah. Waayo, sidoo kale waxaa loo isticmaali karaa in aad u isticmaali karaa in aad isticmaali karaa. Qalabka Tutorial Waxaad ka mid ah ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah. Haku Haku Haku Haku Haku Haku project, schema, auth, and RLS Set up Supabase Qalabka dhismaha iyo dhismaha iyo dhismaha Shuruudaha dhismaha model oo ku yaalaa roles iyo shuruudaha in Permit.io Shuruudaha dhismaha iyo dhismaha dhismaha iyo dhismaha Shuruudaha dhismaha ah ee macluumaadka macluumaadka iyo macluumaadka macluumaadka Waayo, waxaan bixiyaan - Setting up Supabase in the Project Shuruudaha ugu horeysay ee loo yaqaan "Supabase" ee Project Ku saabsan Clone the Starter Template Waxaan ka mid ahaysaa a Haku iyo codka oo dhan oo aad u baahan tahay in ay ku faraxsanay Supabase iyo Permit.io. Qalabka Temple GitHub Waxaad ka mid ah u baahan tahay in ay ka mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah. git clone <https://github.com/permitio/supabase-fine-grained-authorization> Ka dib markii aad cloney Project, navigate to the project directory and install the dependencies: cd realtime-polling-app-nextjs-supabase-permitio npm install Shirkadda cusub ee Supabase Sida loo helo: Haku Haku Haku Waayo, waxaa laga yaqaan https://supabase.com oo ka soo xiriir ama loo helo account. Click "Project New" iyo soo dejisan in loo yaqaan Project Name, Password, iyo Region. Sida loo isticmaalo, go'aanshaha Project Settings → API iyo ku saabsan URL-ka Project iyo Anon Key - aad u baahan tahay in ka hor. Qalabka dhismaha iyo dhismaha dhismaha ee Supabase Waxaan isticmaali karaa email/password auth ee Supabase: Haku Haku Haku Haku Waayo, waxaa laga yaqaan Authentication → Providers. Ku saabsan Email Provider (Qalabka) Waayo, waxaa loo isticmaali karaa in ay ka mid ah wax soo saarka iyo wax soo saarka. Qalabka dhismaha database Taageerada waxaa loo isticmaali karaa 3 tababarka ugu weyn: Haku iyo Marka loo isticmaali Ku saabsan dhismaha dhismaha dhismaha dhismaha dhismaha dhismaha dhismaha dhismaha dhismaha polls options votes SQL Editor -- Create a polls table CREATE TABLE polls ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, question TEXT NOT NULL, created_by UUID REFERENCES auth.users(id) NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()), creator_name TEXT NOT NULL, expires_at TIMESTAMP WITH TIME ZONE NOT NULL, ); -- Create an options table CREATE TABLE options ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, poll_id UUID REFERENCES polls(id) ON DELETE CASCADE, text TEXT NOT NULL, ); -- Create a votes table CREATE TABLE votes ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, poll_id UUID REFERENCES polls(id) ON DELETE CASCADE, option_id UUID REFERENCES options(id) ON DELETE CASCADE, user_id UUID REFERENCES auth.users(id), created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()), UNIQUE(poll_id, user_id) ); Shuruudaha Role Level Security (RLS) Enable Sida loo yaqaan 'Politics' waxaa laga yaqaan 'Politics': QEEBE -- Polls policies ALTER TABLE polls ENABLE ROW LEVEL SECURITY; CREATE POLICY "Anyone can view polls" ON polls FOR SELECT USING (true); CREATE POLICY "Authenticated users can create polls" ON polls FOR INSERT TO authenticated WITH CHECK (auth.uid() = created_by); -- Options policies ALTER TABLE options ENABLE ROW LEVEL SECURITY; CREATE POLICY "Anyone can view options" ON options FOR SELECT USING (true); CREATE POLICY "Poll creators can add options" ON options FOR INSERT TO authenticated WITH CHECK ( EXISTS ( SELECT 1 FROM polls WHERE id = options.poll_id AND created_by = auth.uid() ) ); -- Votes policies ALTER TABLE votes ENABLE ROW LEVEL SECURITY; CREATE POLICY "Anyone can view votes" ON votes FOR SELECT USING (true); CREATE POLICY "Authenticated users can vote once" ON votes FOR INSERT TO authenticated WITH CHECK ( auth.uid() = user_id AND NOT EXISTS ( SELECT 1 FROM polls WHERE id = votes.poll_id AND created_by = auth.uid() ) ); Sida loo isticmaali karaa macluumaadka real-time ee Supabase: Haku Haku Sida loo yaqaan 'Table Editor' Waayo, waxaa laga yaabaa in ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah. Soo dejisan Email Authentication ee App Marka aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay. Haku: .env.local NEXT_PUBLIC_SUPABASE_URL=your_supabase_url NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key Waqtiga login aad si ay u soo saarka iyo login via email / password: import { useState } from "react"; import { createClient } from "@/utils/supabase/component"; const LogInButton = () => { const supabase = createClient(); async function logIn() { const { error } = await supabase.auth.signInWithPassword({ email, password, }); if (error) { setError(error.message); } else { setShowModal(false); } } async function signUp() { const { error } = await supabase.auth.signUp({ email, password, options: { data: { user_name: userName, }, }, }); if (error) { setError(error.message); } else { setShowModal(false); } } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(""); if (isLogin) { await logIn(); } else { await signUp(); } }; return ( <> <button onClick={() => setShowModal(true)} className="flex items-center gap-2 p-2 bg-gray-800 text-white rounded-md"> Log In </button> ... </> ); }; export default LogInButton; Sida loo isticmaali karaa Supabase's Sida loo isticmaali karaa user iyo ka mid ah si ay u isticmaali karaa user cusub ee email iyo password. We are also storing the user's name in Nala soo xiriir Metadata user. signInWithPassword signUp user_name Waxaad sidoo kale isticmaali karaa Waayo, waxaa loo isticmaali karaa in la isticmaali karaa in la isticmaali karaa. supabase.auth.signOut() import { createClient } from "@/utils/supabase/component"; import { useRouter } from "next/router"; const LogOutButton = ({ closeDropdown }: { closeDropdown: () => void }) => { const router = useRouter(); const supabase = createClient(); const handleLogOut = async () => { await supabase.auth.signOut(); closeDropdown(); router.push("/"); }; return ( ... ); }; export default LogOutButton; Sidaa waxaa loo isticmaali karaa nidaamka oo ka mid ah Supabase si ay u hesho user iyo si ay u mid ah home page. signOut Qalabka dhismaha iyo dhismaha dhismaha iyo dhismaha Shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha ugu horeysay ee shuruudaha. Haku Haku Haku Show/hide elements UI sida login/logout buttons Shuruudaha dhismaha iyo dhismaha iyo dhismaha iyo dhismaha Ensure only authenticated users can perform restricted actions Waxaan u isticmaali karaa to listen to these events and update the app accordingly. supabase.auth.onAuthStateChange() Haku Haku In the Layout.tsx file: Track Global Auth State import React, { useEffect, useState } from "react"; import { createClient } from "@/utils/supabase/component"; import { User } from "@supabase/supabase-js"; const Layout = ({ children }: { children: React.ReactNode }) => { const [user, setUser] = useState<User | null>(null); useEffect(() => { const fetchUser = async () => { const supabase = createClient(); const { data } = supabase.auth.onAuthStateChange((event, session) => { setUser(session?.user || null); }); return () => { data.subscription.unsubscribe(); }; }; fetchUser(); }, []); return ( ... ); }; export default Layout; Waayo, waxaa laga yaabaa in la soo bandhigay. Sidaas sida Marka Waxaad ka mid ka mid ah in la soo bandhigay in la soo bandhigay in la soo bandhigay in la soo bandhigay in la soo bandhigay. poll details poll management Sidaa waxaa loo heli karaa in : pages/polls/[id].tsx import { createClient } from "@/utils/supabase/component"; import { User } from "@supabase/supabase-js"; const Page = () => { const [user, setUser] = useState<User | null>(null); useEffect(() => { const fetchUser = async () => { const supabase = createClient(); const { data } = supabase.auth.onAuthStateChange((event, session) => { setUser(session?.user || null); setLoading(false); }); return () => { data.subscription.unsubscribe(); }; }; fetchUser(); }, []); return ( ... ); export default Page; Sida loo isticmaali karaa in , oo isticmaalka waa in la soo xiriir oo ka mid ah wax soo saarka: pages/polls/manage.tsx import { createClient } from "@/utils/supabase/component"; import { User } from "@supabase/supabase-js"; const Page = () => { const [user, setUser] = useState<User | null>(null); const supabase = createClient(); useEffect(() => { const fetchUser = async () => { const { data } = supabase.auth.onAuthStateChange((event, session) => { setUser(session?.user || null); if (!session?.user) { setLoading(false); } }); return () => { data.subscription.unsubscribe(); }; }; fetchUser(); }, []); return ( ... ); }; export default Page; These patterns ensure your UI reflects the user’s current authentication status and form the basis for the authorization checks we'll add later. For example, you’ll later use this object when calling the Shuruudaha Edge waa in ay u baahan tahay in ay isticmaali karaa in la heli karaa ama in la isticmaali karaa in la isticmaali karaa in la isticmaali karaa. user checkPermission Qalabka Qalabka Polling With Supabase configured and authentication working, we can now build the core functionality of the polling app. In this section, we’ll cover: Haku Haku Haku Qalabka cusub Qalabka dhismaha iyo dhismaha dhismaha iyo dhismaha dhismaha Sida loo isticmaali karaa nidaamka dhismaha Waxaad ku dhigi karaa in ay ku dhigi karaa in ay ka mid ah wax soo saarka ah oo ka mid ah wax soo saarka ah. Nala soo xiriir Users must be logged in to create polls. Each poll includes a question, an expiration date, and a set of options. We also record who created the poll so we can later use that relationship for access control. Inside Shuruudaha dhismaha iyo dhismaha dhismaha iyo dhismaha dhismaha iyo dhismaha NewPoll.tsx import React, { useEffect, useState } from "react"; import { createClient } from "@/utils/supabase/component"; import { User } from "@supabase/supabase-js"; const NewPoll = () => { const [user, setUser] = useState<User | null>(null); const supabase = createClient(); useEffect(() => { const fetchUser = async () => { const supabase = createClient(); const { data } = supabase.auth.onAuthStateChange((event, session) => { setUser(session?.user || null); }); return () => { data.subscription.unsubscribe(); }; }; fetchUser(); }, []); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (question.trim() && options.filter(opt => opt.trim()).length < 2) { setErrorMessage("Please provide a question and at least two options."); return; } // Create the poll const { data: poll, error: pollError } = await supabase .from("polls") .insert({ question, expires_at: new Date(expiryDate).toISOString(), created_by: user?.id, creator_name: user?.user_metadata?.user_name, }) .select() .single(); if (pollError) { console.error("Error creating poll:", pollError); setErrorMessage(pollError.message); return; } // Create the options const { error: optionsError } = await supabase.from("options").insert( options .filter(opt => opt.trim()) .map(text => ({ poll_id: poll.id, text, })) ); if (!optionsError) { setSuccessMessage("Poll created successfully!"); handleCancel(); } else { console.error("Error creating options:", optionsError); setErrorMessage(optionsError.message); } }; return ( ... ); }; export default NewPoll; Waayo, waxaan ka dibna soo xiriir Function Edge ee loo yaqaan "creator" ee Permit.io. Shuruudaha iyo wax soo saarka Qalabka waxaa laga yaabaa in (wax ka mid ah) iyo (expired). You can fetch them using Supabase queries filtered by the current timestamp, and set up real-time subscriptions to reflect changes instantly. active past Example from Haku: pages/index.tsx import { PollProps } from "@/helpers"; import { createClient } from "@/utils/supabase/component"; export default function Home() { const supabase = createClient(); useEffect(() => { const fetchPolls = async () => { setLoading(true); const now = new Date().toISOString(); try { // Fetch active polls const { data: activePolls, error: activeError } = await supabase .from("polls") .select( ` id, question, expires_at, creator_name, created_by, votes (count) ` ) .gte("expires_at", now) .order("created_at", { ascending: false }); if (activeError) { console.error("Error fetching active polls:", activeError); return; } // Fetch past polls const { data: expiredPolls, error: pastError } = await supabase .from("polls") .select( ` id, question, expires_at, creator_name, created_by, votes (count) ` ) .lt("expires_at", now) .order("created_at", { ascending: false }); if (pastError) { console.error("Error fetching past polls:", pastError); return; } setCurrentPolls(activePolls); setPastPolls(expiredPolls); } catch (error) { console.error("Unexpected error fetching polls:", error); } finally { setLoading(false); } }; fetchPolls(); // Set up real-time subscription on the polls table: const channel = supabase .channel("polls") .on( "postgres_changes", { event: "*", schema: "public", table: "polls", }, fetchPolls ) .subscribe(); return () => { supabase.removeChannel(channel); }; }, []); return ( ... ); } Viewing and Managing User Polls Sida loo yaabaa, waxaa loo yaabaa in ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah. Waxaan sidoo kale ku habboonay in ay ku habboonay in ay ku habboonay in ay ku habboonay in ay ku habboonay table so that we can update the UI with the latest poll data. To differentiate between active and past polls, we are comparing the expiry date of each poll with the current date. polls polls Update the page to fetch and display only polls created by the user: pages/manage.tsx import { PollProps } from "@/helpers"; const Page = () => { useEffect(() => { if (!user?.id) return; const fetchPolls = async () => { try { const { data, error } = await supabase .from("polls") .select( ` id, question, expires_at, creator_name, created_by, votes (count) ` ) .eq("created_by", user.id) .order("created_at", { ascending: false }); if (error) { console.error("Error fetching polls:", error); return; } setPolls(data || []); } catch (error) { console.error("Unexpected error fetching polls:", error); } finally { setLoading(false); } }; fetchPolls(); // Set up real-time subscription const channel = supabase .channel(`polls_${user.id}`) .on( "postgres_changes", { event: "*", schema: "public", table: "polls", filter: `created_by=eq.${user.id}`, }, fetchPolls ) .subscribe(); return () => { supabase.removeChannel(channel); }; }, [user]); return ( ... ); }; export default Page; Sidaa, waxaan ka mid ah ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah. Taageerada waxaa laga yaabaa in la soo xiriir in ay ku saabsan macluumaadka macluumaadka macluumaadka. polls Sida loo update component so that if a logged-in user is the poll creator, icons for editing and deleting the poll will be displayed to them on the poll. PollCard import { createClient } from "@/utils/supabase/component"; import { User } from "@supabase/supabase-js"; const PollCard = ({ poll }: { poll: PollProps }) => { const [user, setUser] = useState<User | null>(null); useEffect(() => { const supabase = createClient(); const fetchUser = async () => { const { data } = supabase.auth.onAuthStateChange((event, session) => { setUser(session?.user || null); setLoading(false); }); return () => { data.subscription.unsubscribe(); }; }; fetchUser(); }, []); return ( ... )} </Link> ); }; export default PollCard; Sida loo yaabaa, waxaa loo yaabaa in ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ka mid ah. Sida loo isticmaalo nidaamka Poll Voting The voting logic enforces: Haku Haku Haku Haku Haku Only one vote per user per poll Creators cannot vote on their own polls Haku waxay ku salaysan tababarka dhismaha Results are displayed and updated in real time Sida loo isticmaali karaa in ay loo isticmaali karaa Haku: ViewPoll.tsx We need the current user’s ID to determine voting eligibility and record their vote. Fetch the Logged-In User import { createClient } from "@/utils/supabase/component"; import { User } from "@supabase/supabase-js"; const ViewPoll = () => { const [user, setUser] = useState<User | null>(null); const supabase = createClient(); useEffect(() const fetchUser = async () => { const { data: { user }, } = await supabase.auth.getUser(); setUser(user); }; fetchUser(); }, []); Once we have the user, we fetch: Load Poll Details and Check Voting Status Haku Haku Haku Qalabka dhismaha (ka mid ka mid ka mid ka mid ka mid ka mid ka mid ka mid ah) Whether this user has already voted Waxaan sidoo kale soo xiriir in uu ku saabsan updates real-time. useEffect(() => { if (!user) { return; } const checkUserVote = async () => { const { data: votes } = await supabase .from("votes") .select("id") .eq("poll_id", query.id) .eq("user_id", user.id) .single(); setHasVoted(!!votes); setVoteLoading(false); }; const fetchPoll = async () => { const { data } = await supabase .from("polls") .select( ` *, options ( id, text, votes (count) ) ` ) .eq("id", query.id) .single(); setPoll(data); setPollLoading(false); checkUserVote(); }; fetchPoll(); Listen for Real-Time Updates Waayo, waxaan ka soo bandhigay in ay ka mid ah wax soo saarka. table, scoped to this poll. When a new vote is cast, we fetch updated poll data and voting status. votes const channel = supabase .channel(`poll-${query.id}`) .on( "postgres_changes", { event: "*", schema: "public", table: "votes", filter: `poll_id=eq.${query.id}`, }, () => { fetchPoll(); checkUserVote(); } ) .subscribe(); return () => { supabase.removeChannel(channel); }; }, [query.id, user]); Handle the Vote Submission If user has not voted and is allowed to vote (we’ll add a permission check later), we’ll insert his vote. const handleVote = async (optionId: string) => { if (!user) return; try { const { error } = await supabase.from("votes").insert({ poll_id: query.id, option_id: optionId, user_id: user.id, }); if (!error) { setHasVoted(true); } } catch (error) { console.error("Error voting:", error); } }; Waayo, waxaa loo isticmaali karaa in ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah. Display the Poll Results if (!poll || pollLoading || voteLoading) return <div>Loading...</div>; // 6. calculate total votes const totalVotes = calculateTotalVotes(poll.options); const countdown = getCountdown(poll.expires_at); return ( ... ); }; export default ViewPoll; Sida loo isticmaali karaa, nidaamka ka mid ah nidaamka ka mid ah nidaamka ka mid ah nidaamka ka mid ah nidaamka ka mid ah nidaamka ka mid ah nidaamka ka mid ah nidaamka ka mid ah. Haku and Waayo, waxaa loo yaabaa in la taabto. authorization checks Permit.io Supabase Edge Functions Before we do that, let’s first look at the type of authorization layer we are going to implement. Understanding ReBAC (Relationship-Based Access Control) Su'aalaha dhismaha iyo dhismaha baska ah ee kala duwan oo ka mid ah dhismaha iyo dhismaha iyo dhismaha. Haku Haku Haku Haku Shuruudaha waxaa laga yaabaa in la soo bandhigiisa in la soo bandhigiisa. Assigning per-resource roles (like “creator” for a specific poll) Managing access via external policies Waayo, waxaa loo yaqaan 'Relationship-based permissions', waxaan u isticmaali karaa ReBAC iyo Permit.io. ReBAC waa mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah. ReBAC (Relationship-Based Access Control) waa mid ka mid ah ReBAC (Relationship-Based Access Control) waa mid ka mid ah In this tutorial, we apply ReBAC to a polling app: Haku Haku A user who a poll is the only one who can manage (edit/delete) it created Waxaa la heli karaa in la soo bandhigiisa. Muuqaalka macaamiisha waxaa laga heli karaa 1 toddobaad per poll By modeling these relationships in Permit.io, we can define fine-grained access rules that go beyond Supabase’s built-in Row Level Security (RLS). We’ll enforce them at runtime using Supabase Edge Functions and Permit’s policy engine. Ma rabtaa in uu ku saabsan ReBAC, check out Haku Haku.io oo ku saabsan ReBAC Qalabka Access Control Sida loo isticmaali karaa app, waxaan loo isticmaali karaa: Haku Sida loo yaabaa in ay ka mid ah mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah. Dhammaan waxaa laga yaabaa in ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid Nala soo xiriir Permit.io Waayo, sidoo kale waxaa laga yaabaa in la soo saarka model autorization ee Permit. Haku Haku Haku Shirkadda cusub ee Permit.io Name it something like supabase-polling Waayo, waxaa loo isticmaali karaa in ay ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah. ReBAC waxaa laga yaqaan "ReBAC Options" oo loo yaqaan "Role creator authenticated". Nala soo xiriir Navigate to the "Roles" tab to view the roles from the resources we just created. Note that Permit created the default roles ( Haku , ) that are unnecessary for this tutorial. admin editor user Haku Haku Haku Shuruudaha dhismaha Access Go to Policy → Policies Use the visual matrix to define: authenticated can read and create polls creator can read, update, and delete polls (Optional) Waxaad loo isticmaali karaa xisaabooyinka dhismaha sida ka mid ah this ama via a resource second if you model votes separately Add resource instances Go to Directory → Instances Add individual poll IDs as resource instances (wax yar u isticmaali karaa in uu ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ah mid Dhismaha ugu fiican ee loo isticmaali karaa waa in la isticmaali karaa si ay u isticmaali karaa in ay u isticmaali karaa. Sida loo yaabaa in ay ka mid ah wax soo saarka ugu horeysay ee dhismaha Permit, si loo isticmaali karaa in our application. Next, we will connect to our Supabase project via Edge Functions that: Haku.ee Haku Haku Haku Shiinaha user Shuruudaha Creator Qalabka Access on Demand Setting up Permit in the Polling Application Dhammaan waxaa loo isticmaali karaa in ka mid ah macluumaadka, laakiin waxaan loo isticmaali karaa Container PDP for this tutorial.You must host the container online to access it in Supabase Edge functions.You can use services such as Sida loo soo saarka, aad u soo saarka url for your container. Haku: Railway Waayo, waxaa laga yaabaa in ay ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah. Soo dejisan Supabase Edge Function API for Authorization Waayo, waxaa loo isticmaali karaa in la isticmaali karaa adeegga ReBAC oo ka mid ah loo isticmaali karaa si ay u isticmaali karaa si ay u isticmaali karaa si ay u isticmaali karaa si ay u isticmaali karaa. Supabase Edge Functions Create Functions in Supabase Initialise Supabase in your project and create three different functions using the command. These will be the starting point for your functions: supabase functions new npx supabase init npx supabase functions new syncUser npx supabase functions new updateCreatorRole npx supabase functions new checkPermission This will create a Follower ee Marka aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay. functions supabase Syncing Users to Permit.io on Signup ( QEEBE syncUser.ts This function listens for Supabase’s Xisaabinta auth.Wala soo bandhigay user cusub, waxaan soo bandhigi karaa identity-ga Permit.io iyo soo bandhigiisa default. role. SIGNED_UP authenticated import "jsr:@supabase/functions-js/edge-runtime.d.ts"; import { Permit } from "npm:permitio"; const corsHeaders = { 'Access-Control-Allow-Origin': "*", 'Access-Control-Allow-Headers': 'Authorization, x-client-info, apikey, Content-Type', 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS, PUT, DELETE', } // Supabase Edge Function to sync new users with Permit.io Deno.serve(async (req) => { const permit = new Permit({ token: Deno.env.get("PERMIT_API_KEY"), pdp: "<https://real-time-polling-app-production.up.railway.app>", }); try { const { event, user } = await req.json(); // Only proceed if the event type is "SIGNED_UP" if (event === "SIGNED_UP" && user) { const newUser = { key: user.id, email: user.email, name: user.user_metadata?.name || "Someone", }; // Sync the user to Permit.io await permit.api.createUser(newUser); await permit.api.assignRole({ role: "authenticated", tenant: "default", user: user.id, }); console.log(`User ${user.email} synced to Permit.io successfully.`); } // Return success response return new Response( JSON.stringify({ message: "User synced successfully!" }), { status: 200, headers: corsHeaders }, ); } catch (error) { console.error("Error syncing user to Permit: ", error); return new Response( JSON.stringify({ message: "Error syncing user to Permit.", "error": error }), { status: 500, headers: { "Content-Type": "application/json" } }, ); } }); Qalabka Qalabka Qalabka Qalabka Qalabka ( ) updateCreatorRole.ts Ka dib markii isticmaalka loo loo soo saarka, function this is called to: Haku Haku Qalabka dhismaha iyo dhismaha dhismaha iyo dhismaha Shuruudaha ugu horeysay ee ay ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah Qalabka Qalabka ( QEEBE checkPermission.ts Marka aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u isticmaali karaa ( , , Haku (Haddii loo yaqaan 'Poll' waa mid ka mid ah wax soo saarka. create read update delete import "jsr:@supabase/functions-js/edge-runtime.d.ts"; import { Permit } from "npm:permitio"; const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "Authorization, x-client-info, apikey, Content-Type", "Access-Control-Allow-Methods": "POST, GET, OPTIONS, PUT, DELETE", }; Deno.serve(async req => { const permit = new Permit({ token: Deno.env.get("PERMIT_API_KEY"), pdp: "<https://real-time-polling-app-production.up.railway.app>", }); try { const { userId, operation, key } = await req.json(); // Validate input parameters if (!userId || !operation || !key) { return new Response( JSON.stringify({ error: "Missing required parameters." }), { status: 400, headers: { "Content-Type": "application/json" } } ); } // Check permissions using Permit's ReBAC const permitted = await permit.check(userId, operation, { type: "polls", key, tenant: "default", // Include any additional attributes that Permit needs for relationship checking attributes: { createdBy: userId, // This will be used in Permit's policy rules }, }); return new Response(JSON.stringify({ permitted }), { status: 200, headers: corsHeaders, }); } catch (error) { console.error("Error checking user permission: ", error); return new Response( JSON.stringify({ message: "Error occurred while checking user permission.", error: error, }), { status: 500, headers: { "Content-Type": "application/json" } } ); } }); Qalabka Local Start your Supabase dev server to test the functions locally: npx supabase start npx supabase functions serve Waxaad ka mid ah u shaqeeyaan: <http://localhost:54321/functions/v1/><function-name> Haku: <http://localhost:54321/functions/v1/checkPermission> Qalabka Qalabka Qalabka Qalabka Qalabka Qalabka Qalabka Qalabka Qalabka Tani oo aan loo isticmaali karaa logic autorization ee Permit.io iyo loo isticmaali karaa via Supabase Edge Functions, waxaa laga yaabaa in la isticmaali karaa wax soo saarka ah ee app. In this section, waxaan soo dejiso components UI key si ay u soo xiriir macluumaadka iyo si ay u isticmaali karaa ama si ay u isticmaali karaa macluumaadka user sida si ay u heli karaa ama si ay u isticmaali karaa macluumaadka. Role Creator (Role Creator) ka dib markii loo helo NewPoll.tsx NewPoll.tsx After creating a poll and saving it to Supabase, we call the Qalabka 2: updateCreatorRole Haku Haku Sida loo yaqaan 'Poll' waa mid ka mid ah 'Permit.io'. Ma rabtaa in aad Cudarada in aad Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada : Waayo, waxaa laga yaabaa in la soo bandhigay in la soo bandhigay ViewPoll.tsx Ka dib markii loo isticmaali karaa in la soo bandhigiisa, waxaan la soo bandhigiisa Qalabka waa in ay u hesho Qalabka Qalabka Haku: Sida loo isticmaali karaa loo isticmaali karaa: checkPermission create votes “A creator cannot vote on their own poll.” Check voting permission: const [canVote, setCanVote] = useState(false); useEffect(() => { const checkPermission = async () => { if (!user || !query.id) return; try { const response = await fetch("<http://127.0.0.1:54321/functions/v1/checkPermission>", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ userId: user.id, operation: "create", key: query.id, }), }); const { permitted } = await response.json(); setCanVote(permitted); } catch (error) { console.error("Error checking permission:", error); setCanVote(false); } }; checkPermission(); }, [user, query.id]); Disable vote buttons if user isn’t allowed: <button onClick={() => handleVote(option.id)} disabled={!user || !canVote}} className="w-full text-left p-4 rounded-md hover:bg-slate-100 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"> {option.text} </button> Show a message if the user is not allowed to vote: {user && !canVote && ( <p className="mt-4 text-gray-600">You cannot vote on your own poll</p> )} : Control Access si aad u soo saarka Edit/Delete PollCard.tsx Waxaan sidoo kale ku raaxo xanuunka xanuunka xanuunka (xanuunka iyo xanuunka) by checking if user has the Marka Qiyaasta oo ku saabsan this poll. update delete Check management permissions: const [canManagePoll, setCanManagePoll] = useState(false); useEffect(() => { const checkPollPermissions = async () => { if (!user || !poll.id) return; try { // Check for both edit and delete permissions const [editResponse, deleteResponse] = await Promise.all([ fetch("<http://127.0.0.1:54321/functions/v1/checkPermission>", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ userId: user.id, operation: "update", key: poll.id, }), }), fetch("/api/checkPermission", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ userId: user.id, operation: "delete", key: poll.id, }), }), ]); const [{ permitted: canEdit }, { permitted: canDelete }] = await Promise.all([editResponse.json(), deleteResponse.json()]); // User can manage poll if they have either edit or delete permission setCanManagePoll(canEdit || canDelete); } catch (error) { console.error("Error checking permissions:", error); setCanManagePoll(false); } }; checkPollPermissions(); }, [user, poll.id]); Conditionally show management buttons: Haku: {user?.id === poll?.created_by && ( Marka: {canManagePoll && ( <div className="flex justify-start gap-4 mt-4"> <button type="button" onClick={handleEdit}> </button> <button type="button" onClick={handleDelete}> </button> </div> )} Testing the Integration Sida loo isticmaali karaa, sidoo kale loo isticmaali karaa in la isticmaali karaa in la isticmaali karaa in la isticmaali karaa. Haku Haku Haku Haku Waayo, waxaa loo isticmaali karaa mid ka mid ah macluumaadka iyo mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah. Waayo, waxaa laga yaabaa in la soo bandhigiisa in la soo bandhigiisa in la soo bandhigiisa. Waayo, waxaa lagu soo bandhigay in la soo bandhigay. Only creators see edit/delete options on their polls. Ma rabtaa in aad si aad u aragto wax soo saarka ah oo aad u aragto in aad u aragto in aad u aragto in aad u aragto. Marka aad u isticmaali kartaa in aad u isticmaali kartaa in aad u isticmaali kartaa in aad isticmaali kartaa in aad isticmaali kartaa in aad isticmaali kartaa in aad isticmaali kartaa in aad isticmaali kartaa in aad isticmaali kartaa in aad isticmaali kartaa in aad isticmaali kartaa in aad isticmaali kartaa in aad isticmaali kartaa in aad isticmaali kartaa in aad isticmaali kartaa in aad isticmaali karaa. Qalabka In this tutorial, waxaan ka heli karaa sida loo isticmaali karaa Waayo, waxaa loo yaqaan 'real world' adeegyada Supabase authentication and authorization Next.js Waayo, waxaan ka soo bandhigay Waayo, waxaa loo yaqaan 'Relational Scheme' iyo 'Row Level Security' iyo 'Dynamic Authorization Logic'. Sida loo isticmaali karaa iyo a Markaas oo ka mid ah wax soo saarka ah, waxaan ka mid ah wax soo saarka iyo wax soo saarka iyo wax soo saarka. Supabase Auth ReBAC Supabase Edge Functions Policy Decision Point (PDP) Sida loo isticmaali karaa Sida loo isticmaali karaa qalabka flexible, waxaan noqon doonaa: Supabase Auth Haku Haku Haku Haku Waayo, waxaa loo isticmaali karaa in ay u isticmaali karaa email iyo password. Shuruudaha dhismaha iyo shuruudaha dhismaha ka mid ah macaamiisha Waayo, waxaa loo yaabaa in la soo bandhigiisa in la soo bandhigiisa in la soo bandhigiisa. Assign and evaluate user roles based on relationships to data Sida loo yaabaa, waxaa laga yaabaa in ay ka mid ah wax soo saarka iyo wax soo saarka, oo ka mid ah wax soo saarka iyo wax soo saarka. Qalabka Haku Haku Haku Haku Haku Haku Haku: ReBAC Guide Shuruudaha Qalabka + Authentication Shuruudaha Xirfadiga: Xirfadiga Xirfadiga Xirfadiga Filter dhismaha Qalabka Ma rabtaa wax soo saarka? , oo hundred ka mid ah shuruudaha waa la aasaasay iyo dib u hesho autorization. Slack community Slack community